package me.hacket.netrequestpro.base;

import java.io.UnsupportedEncodingException;
import java.lang.reflect.Type;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Map;

import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;

import android.support.annotation.NonNull;
import android.text.TextUtils;
import me.hacket.library.HNetConfig;
import me.hacket.library.util.LogUtils;

/**
 * 构建post url的请求参数 ( 注意是跟在url后面的参数, 不是post body )
 */
public class CommonParams {

    private static final String TAG = CommonParams.class.getSimpleName();

    private static final String DEFAULT_CHARSET = "utf-8";
    private static final String QMARK = "?";

    private String mBaseUrl;
    private String mPathUrl;
    private boolean isNeedCommonParams;
    private Map<String, String> mParams = new HashMap<>();

    private CommonParams(Builder builder) {
        this.mBaseUrl = builder.mBaseUrl;
        this.mPathUrl = builder.mPathUrl;
        this.isNeedCommonParams = builder.isNeedCommonParams;
        this.mParams = builder.mParams;
    }

    /**
     * 构建url
     *
     * @return baseUrl+pathUrl+参数的url
     */
    public String buildUrl() {
        StringBuilder sb = new StringBuilder();

        if (TextUtils.isEmpty(mBaseUrl)) {
            throw new IllegalArgumentException("the baseUrl must not be null !");
        }
        sb.append(mBaseUrl);

        if (!TextUtils.isEmpty(mPathUrl)) {
            sb.append(mPathUrl);
        }

        Map<String, String> buildAllParams = buildAllParams();
        if (!buildAllParams.isEmpty()) {
            sb.append(QMARK);
            sb.append(encodeParamsToStr(buildAllParams, DEFAULT_CHARSET));
        }

        LogUtils.i(TAG, "buildUrl , url : " + sb.toString());
        return sb.toString();
    }

    /**
     * 构建通用参数+自定义参数
     *
     * @return 通用参数+自定义参数的Map
     */
    private Map<String, String> buildAllParams() {
        if (isNeedCommonParams) {
            mParams.putAll(buildCommonParams());
        }
        return mParams;
    }

    /**
     * 构建通用参数
     *
     * @return
     */
    private Map<String, String> buildCommonParams() {
        RequestCommonParams.Builder builder = new RequestCommonParams.Builder();
        return generateBodyMap(builder.build());
    }

    /**
     * Bean转换成Map
     *
     * @param bodyRequest
     * @param <T>
     *
     * @return
     */
    private <T> HashMap<String, String> generateBodyMap(T bodyRequest) {
        String bodyJson = new Gson().toJson(bodyRequest);
        LogUtils.i(HNetConfig.TAG, "generateRequest params :" + bodyJson);
        Type type = new TypeToken<HashMap<String, T>>() {
        }.getType();
        HashMap<String, String> body = new Gson().fromJson(bodyJson, type);
        return body;
    }

    /**
     * Map转成String
     * <p>
     * Converts <code>params</code> into an application/x-www-form-urlencoded encoded string.
     */
    private static String encodeParamsToStr(Map<String, String> params, String paramsEncoding) {
        StringBuilder encodedParams = new StringBuilder();
        try {
            int i = 0;
            for (Map.Entry<String, String> entry : params.entrySet()) {
                encodedParams.append(URLEncoder.encode(entry.getKey(), paramsEncoding));
                encodedParams.append('=');
                encodedParams.append(URLEncoder.encode(entry.getValue(), paramsEncoding));
                if (i != params.size() - 1) {
                    encodedParams.append('&');
                }
                i++;
            }
            return encodedParams.toString();
        } catch (UnsupportedEncodingException uee) {
            throw new RuntimeException("Encoding not supported: " + paramsEncoding, uee);
        }
    }

    /**
     * 通用参数
     */
    public static final class RequestCommonParams {
        private String user_id;
        private String token;
        private String user_type;
        private String chain_id;
        private String timestamp;
        private String client_device;
        private String client_config_version;
        private String client_channel;
        private String client_version;

        private RequestCommonParams(Builder builder) {
            this.user_id = builder.user_id;
            this.token = builder.token;
            this.user_type = builder.user_type;
            this.chain_id = builder.chain_id;
            this.timestamp = builder.timestamp;
            this.client_device = builder.client_device;
            this.client_config_version = builder.client_config_version;
            this.client_channel = builder.client_channel;
            this.client_version = builder.client_version;
        }

        public static final class Builder {
            private String user_id = "sale000000000004";
            private String token = "d0111d62638511e6b2becaed6cf9a56e";
            private String user_type = "sale";
            private String chain_id = "a2b9ad937dd9c50ddbe223ec985ce548";
            private String timestamp = "20160816161458";
            private String client_device = "android";
            private String client_config_version = "1100";
            private String client_channel = "useuscs";
            private String client_version = "1.1.0.0";

            public Builder setUserId(@NonNull String userId) {
                this.user_id = userId;
                return this;
            }

            public Builder setToken(@NonNull String token) {
                this.token = token;
                return this;
            }

            public Builder setUserType(@NonNull String user_type) {
                this.user_type = user_type;
                return this;
            }

            public Builder setChainId(@NonNull String chain_id) {
                this.chain_id = chain_id;
                return this;
            }

            public Builder setTimestamp(@NonNull String timestamp) {
                this.timestamp = timestamp;
                return this;
            }

            public Builder setClientDevice(@NonNull String client_device) {
                this.client_device = client_device;
                return this;
            }

            public Builder setClientConfigVersion(@NonNull String client_config_version) {
                this.client_config_version = client_config_version;
                return this;
            }

            public Builder setClientChannel(@NonNull String client_channel) {
                this.client_channel = client_channel;
                return this;
            }

            public Builder setClientVersion(@NonNull String client_version) {
                this.client_version = client_version;
                return this;
            }

            public RequestCommonParams build() {
                return new RequestCommonParams(this);
            }
        }
    }

    public static final class Builder {
        private String mBaseUrl;
        private String mPathUrl;
        private boolean isNeedCommonParams = true;
        private Map<String, String> mParams = new HashMap<>();

        public Builder baseUrl(@NonNull String baseUrl) {
            this.mBaseUrl = baseUrl;
            return this;
        }

        public Builder pathUrl(@NonNull String pathUrl) {
            this.mPathUrl = pathUrl;
            return this;
        }

        /**
         * 是否需要公共参数
         *
         * @param isNeedCommonParams boolean
         *
         * @return Builder
         */
        public Builder isNeedCommonParams(@NonNull boolean isNeedCommonParams) {
            this.isNeedCommonParams = isNeedCommonParams;
            return this;
        }

        /**
         * 添加自定义参数
         *
         * @param params params
         *
         * @return Builder
         */
        public Builder addParams(Map<String, String> params) {
            if (params != null && !params.isEmpty()) {
                mParams.putAll(params);
            }
            return this;
        }

        /**
         * 添加自定义参数
         *
         * @param key   key
         * @param value value
         *
         * @return Builder
         */
        public Builder addParam(@NonNull String key, String value) {
            if (!TextUtils.isEmpty(key)) {
                mParams.put(key, value);
            }
            return this;
        }

        public CommonParams build() {
            return new CommonParams(this);
        }
    }

}